package icu.javayanglei.bilibili.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.IdUtil;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 文件工具类
 *
 * @author yang
 * @version 1.0.0
 * @date 2022-01-11 01:40
 */
public class MyFileUtil {
    public static File createTemp() {
        return FileUtil.createTempFile("export", ".tmp", FileUtil.getTmpDir(), true);
    }

    /**
     * 创建一个 PDF 文件，在临时目录上
     *
     * @return 创建的文件
     */
    public static File createPdf() {
        return FileUtil.createTempFile("export", ".pdf", FileUtil.getTmpDir(), true);
    }

    /**
     * 创建一个 Excel 文件，在临时目录上
     *
     * @return 创建的文件
     */
    public static File createExcel() {
        return FileUtil.createTempFile("export", ".xlsx", FileUtil.getTmpDir(), true);
    }

    /**
     * 创建一个 Word 文件，在临时目录上
     *
     * @return 创建的文件
     */
    public static File createWord() {
        return FileUtil.createTempFile("docx", ".docx", FileUtil.getTmpDir(), true);
    }

    /**
     * MultipartFile to File
     *
     * @param multipartFile 目标文件
     * @return 转换后的 File 文件
     */
    public static File toFile(MultipartFile multipartFile) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = "." + FileUtil.extName(fileName);
        File file = null;
        try {
            // 用uuid作为文件名，防止生成的临时文件重复
            file = File.createTempFile(IdUtil.simpleUUID(), prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 下载文件名中含有中文的处理
     *
     * @param req      域
     * @param headName 文件名
     * @return 转码后的文件名
     */
    public static String encodeFileName(HttpServletRequest req, String headName)
            throws UnsupportedEncodingException {
        //IE9之前包括IE9都包含MSIE;IE10之后都包含Trident; edge浏览器包含Edge
        String msie = "MSIE";
        String trident = "Trident";
        String edge = "Edge";
        String filename = "";
        String userAgent = req.getHeader("User-Agent");
        if (userAgent.contains(msie) || userAgent.contains(trident) || userAgent.contains(edge)) {
            filename = URLEncoder.encode(headName, String.valueOf(StandardCharsets.UTF_8));
        } else {
            filename = new String(headName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        return filename;
    }

    /**
     * 导出 工具
     *
     * @param file     文件
     * @param response response
     * @param request  request
     */
    public static void exportFile(File file, HttpServletResponse response, HttpServletRequest request) throws IOException {

        final FileReader reader = new FileReader(file);
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/x-download");
        response.addHeader("Content-Disposition", "attachment;filename=" + MyFileUtil.encodeFileName(request, FileUtil.getName(file)));
        response.addHeader("Content-Length", String.valueOf(FileUtil.size(file)));
        response.setContentType("application/octet-stream;charset=UTF-8");
        final ServletOutputStream outputStream = response.getOutputStream();
        final BufferedInputStream inputStream = reader.getInputStream();
        IoUtil.copy(inputStream, outputStream);
        // 关闭流
        IoUtil.close(outputStream);
        IoUtil.close(inputStream);
    }

    /**
     * 导出 工具
     *
     * @param file     文件
     * @param fileName 文件名
     * @param response response
     * @param request  request
     */
    public static void exportFile(File file, String fileName, HttpServletResponse response, HttpServletRequest request) throws IOException {
        final FileReader reader = new FileReader(file);
        response.reset();
        response.addHeader("Content-Disposition", "attachment;filename=" + MyFileUtil.encodeFileName(request, fileName));
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/x-download");
        response.addHeader("Content-Length", String.valueOf(FileUtil.size(file)));
        response.setContentType("application/octet-stream;charset=UTF-8");
        final ServletOutputStream outputStream = response.getOutputStream();
        final BufferedInputStream inputStream = reader.getInputStream();
        IoUtil.copy(inputStream, outputStream);
        IoUtil.close(outputStream);
        IoUtil.close(inputStream);
    }

    /**
     * 导出文件
     *
     * @param inputStream 输入流
     * @param fileName    文件名
     * @param response    响应头
     * @param request     请求头
     */
    public static void exportFile(InputStream inputStream, String fileName, HttpServletResponse response, HttpServletRequest request) throws IOException {
        final File touch = FileUtil.touch(fileName);
        final File file = new FileWriter(touch).writeFromStream(inputStream);
        exportFile(file, response, request);
    }

    /**
     * 导出
     *
     * @param bytes    字节
     * @param fileName 文件名
     * @param response 响应流
     * @param request  请求头
     */
    public static void exportFile(byte[] bytes, String fileName, HttpServletResponse response, HttpServletRequest request) throws IOException {
        final File file = FileUtil.touch(fileName);
        FileUtil.writeBytes(bytes, file);
        exportFile(file, response, request);
    }

    /**
     * 下载 pdf 文件
     *
     * @param file         要下载的文件
     * @param response     响应体
     * @param downloadName 文件名，没有后缀
     * @throws IOException 可能 io 异常
     */
    public static void downloadPDF(File file, HttpServletResponse response, String downloadName) throws IOException {
        downloadFileBymsword(file, response, downloadName + ".pdf");
    }

    /**
     * 浏览器下载 excel 文档（单个导出）
     *
     * @param file         文件
     * @param response     response
     * @param downloadName 文件名，不加后缀
     * @throws IOException 可能 io 异常
     */
    public static void downloadExcel(File file, HttpServletResponse response, String downloadName) throws IOException {
        downloadFileBymsword(file, response, downloadName + ".xlsx");
    }

    private static void downloadFileBymsword(File file, HttpServletResponse response, String fileName) throws IOException {
        //提示：在调用工具类生成Word文档之前应当检查所有字段是否完整
        //否则Freemarker的模板殷勤在处理时可能会因为找不到值而报错，这里暂时忽略这个步骤
        InputStream fin = null;
        ServletOutputStream out = null;

        try {
            //调用工具类WordGenerator的createDoc方法生成Word文档
            fin = new FileInputStream(file);

            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msword");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

            out = response.getOutputStream();
            //缓冲区
            byte[] buffer = new byte[1024];
            int bytesToRead = -1;
            // 通过循环将读入的Word文件的内容输出到浏览器中
            while ((bytesToRead = fin.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (fin != null) {
                fin.close();
            }
            if (out != null) {
                out.close();
            }
            if (file != null) {
                // 删除临时文件
                file.delete();
            }
        }
    }

    /**
     * 浏览器下载word文档（单个导出）
     *
     * @param file         文件
     * @param response     response
     * @param downloadName 文件名，不加后缀
     * @throws IOException 可能 io 异常
     */
    public static void downloadWord(File file, HttpServletResponse response, String downloadName) throws IOException {
        downloadFileBymsword(file, response, downloadName + ".docx");
    }

}
